/*
*  This file is part of ygg-brute
*  Copyright (c) 2020 ygg-brute authors
*  See LICENSE for licensing information
*/

#pragma once

#include "common.h"

inline uint32_t shfl(uint32_t x, uint32_t y, uint32_t shift)
{
    return (x << shift) | (y >> (32 - shift));
}

inline uint32_t shfr(uint32_t x, uint32_t y, uint32_t shift)
{
    return (y >> shift) | (x << (32 - shift));
}

inline void node_id_to_ipv6(const uint32_t w[8], uint8_t ipv6[16])
{
    uint32_t cnt = 0;
    uint32_t i = 0;

    for(; i < 4; ++i) {
        if(w[i] == 0xffffffff) {
            cnt += 32;
        } else {
            cnt += clz(~w[i]);
            break;
        }
    }

    i = (cnt + 1) / 32;
    uint32_t shift = (cnt + 1) % 32;

    uint32_t a[4];
    a[0] = shfl(w[i], w[i + 1], shift);
    a[1] = shfl(w[i + 1], w[i + 2], shift);
    a[2] = shfl(w[i + 2], w[i + 3], shift);
    a[3] = shfl(w[i + 3], w[i + 4], shift);
    a[3] = shfr(a[2], a[3], 16);
    a[2] = shfr(a[1], a[2], 16);
    a[1] = shfr(a[0], a[1], 16);
    a[0] >>= 16;

    uint32_t* ip = (uint32_t*)ipv6;
    ip[0] = bswap_u32(a[0] | (cnt << 16) | 0x02000000);
    ip[1] = bswap_u32(a[1]);
    ip[2] = bswap_u32(a[2]);
    ip[3] = bswap_u32(a[3]);
}